<template>
    <div class="cai-method">
        <div class="flexable v-top">
            <div class="method-body auto-grow pr-20">
                <div class="signature">
                    {{ simple (bridge.type) }} {{ bridge.name }} (<template v-if="bridge.parameters && bridge.parameters.length">
                    <template v-for="(param, index) of bridge.parameters" :key="index">
                        <template v-if="index > 0">, </template>
                        {{ simple (param.type) }}
                    </template>
                </template>
                    )
                </div>
                <div class="description" v-if="bridge.description" v-html="bridge.description" />
                <div class="invoke-panel" style="display: none" v-if="bridge.opened">
                    <table class="inv-table">
                        <tr v-for="(param, index) of bridge.parameters" :key="index" :data-index="index">
                            <td class="inv-param-name">
                                <span class="param-name">{{ param.name || '$' + index }}</span>
                                <div class="description">{{ simple (param.type) }}</div>
                            </td>
                            <td class="inv-param-field">
                                <input type="text" class="param-field" :data-type="simple (param.type)"
                                       @focus="clearError (index)" :class="{error: bridge.errors[index]}"
                                       v-model="bridge.args[index]" v-if="isSimple (param.type)">
                                <div style="padding-top: 5px;" v-else-if="isBoolean (param.type)">
                                    <nullable-checkbox v-model="bridge.args[index]"
                                                       :nullable="nullable (param.type)"/>
                                </div>
                                <textarea class="param-field" :data-type="simple (param.type)"
                                          @focus="clearError (index)" :class="{error: bridge.errors[index]}"
                                          v-model="bridge.args[index]" v-else></textarea>
                                <div class="flexable v-center"></div>
                                <div class="description">{{ param.description }}</div>
                            </td>
                        </tr>
                    </table>
                    <div class="flexable v-center">
                        <div class="err-msg auto-grow" v-html="bridge.errorMessage" />
                        <a class="btn btn-secondary" style="font-size: 75%" @click="crossInvoke">
                            <i class="fa fa-play" /> 调用
                        </a>
                    </div>
                </div>
            </div>
            <a class="method-arrow rotate-up" :class="{done: bridge.opened}" @click="toggleTable">
                <i class="fa fa-angle-right" />
            </a>
        </div>
    </div>
</template>

<script>
const SPEC = '<code>null</code>请输入表达式<code>&lt;null&gt;</code>，空串请输入<code>&lt;empty&gt;</code>';

import $ from 'jquery';
import Ajax from "@/utils/Ajax";
import {Bus, metadata} from "@/utils/metadata";

import NullableCheckbox from "@/components/nullable-checkbox.vue";

import {clone, getSimpleName as simple, isBoolean, isSimpleType as isSimple, nullable} from "@/utils/functions";

export default {
    name: 'method-detail',
    props: {method: {type: Object, required: true}},
    components: {NullableCheckbox},
    data () {
        return {
            args: [],
            errors: [],
            errorMessage:'',
            uuid: '',
            bridge: {}
        };
    },
    methods: {
        simple, isSimple, isBoolean, nullable,
        reset () {
            this.args = [];
            this.errors = [];
            this.errorMessage = '';
            delete this.method.opened;
            $ ('.invoke-panel').slideUp ();
        },
        toggleTable (e) {
            if (e) {
                let show = this.bridge.opened;
                if (show) {
                    this.$nextTick (() => {
                        let root = $(e.target).closest ('.cai-method'),
                            panel = root.find ('.invoke-panel');
                        panel.slideUp (() => {
                            this.bridge.opened = false;
                        })
                    });
                } else {
                    this.bridge.opened = true;
                    this.$nextTick (() => {
                        let root = $(e.target).closest ('.cai-method'), panel = root.find ('.invoke-panel');
                        panel.slideDown ();
                    });
                }

            }
        },
        crossInvoke () {
            let i = 0, n = this.bridge.parameters.length, p, v, type, name;
            for (; i < n; i ++) {
                p = this.bridge.parameters [i];
                v = this.bridge.args [i];
                type = simple (p.type).toLowerCase ();
                name = p.name || '$' + i;
                switch (type) {
                    case 'byte':
                    case 'short':
                    case 'int':
                    case 'long':
                        let m = Number (v);
                        if (Math.floor (m) !== m) {
                            this.bridge.errorMessage = '参数' + name + '只能是整数';
                            this.bridge.errors[i] = true;
                            return;
                        }
                        break;

                    case 'float':
                    case 'double':
                        let value = Number (v);
                        if (isNaN (value)) {
                            this.bridge.errors[i] = true;
                            this.bridge.errorMessage = '参数' + name + '只能是数字';
                            return;
                        }
                        break;
                }
            }
            // 如果参数没填满，用 null 补全
            n -= this.bridge.args.length;
            if (n > 0) {
                for (let i = 0; i < n; i ++) {
                    this.bridge.args.push (null);
                }
            }


            let invocation = {
                ...metadata,
                parameters: JSON.stringify (this.bridge.args),
                uuid: this.method.uuid
            };
            Ajax.post ('/apis/backend/remote-call', invocation).then (res => {
                invocation.method = this.method.name;
                Bus.emit ('remote-called', {invocation, res});
            }).catch (({xhr, status, error}) => {
                Bus.emit ('remote-called', {invocation, res: {xhr, status, error, code: xhr.status}})
            });
        },
        clearError (index) {
            this.bridge.errors[index] = false;
            this.bridge.errorMessage  = '';
        }
    },
    mounted () {
        this.bridge = {
            ...clone (this.method),
            args: [], errors:[], errorMessage: ''
        };
    },
    unmounted () {
        delete this.bridge;
    }
};
</script>